<?php

class AccountController extends Controller {

	const SECURE_LOGIN_TIMEOUT = 300;

	public $defaultAction = 'profile';
	public $layout = "//layouts/nomenu";
	public $sendActivationMail = true;

	/**
	 * Specifies the access control rules.
	 * Overrides the default access control rules set in the MemberBaseController class.
	 * @return array access control rules
	 */
	public function accessRules() {
		return array(
			array('allow',
			// allow all users to perform 'index' and 'view' actions
			),
		);
	}

	/**
	 * Declares class-based actions.
	 */
	public function actions() {
		return array(
			// captcha action renders the CAPTCHA image displayed on the contact page
			'captcha' => array(
				'class' => 'CCaptchaAction',
				'backColor' => 0xFFFFFF,
				'testLimit' => 1,
			),
		);
	}

	/**
	 * Activation user account
	 * @return
	 */
	public function actionActivation() {
		$this->layout = '//layouts/index2';

		$username = $_GET['username'];

		$activkey = $_GET['activkey'];

		if ($username && $activkey) {
			$user = User::model()->findByAttributes(array('username' => $username));

			/**
			 * MOBILE VERIFICATION.
			 */
			if (isset($user) && $user->status == User::STATUS_ACTIVE) {
				SystemEvent::add('Activation via Website - Already Completed', 'Username: ' . $user->username, 'Account');
				$this->render('activationAlreadyCompleted');
			} else if ($user->status == User::STATUS_DISABLED) {
				SystemEvent::add('Activation via Website - User Banned', 'Username: ' . $user->username, 'Account');
				$this->render('activationBanned');
			} else if (isset($user->activkey) && ($user->activkey == $activkey)) {
				// first time visiting activation page, send OTP immediately.
				if (empty($user->mobile_authtoken)) {
					$this->sendOTP($user);
				}

				// User clicks on 'Send OTP to mobile', send Verification code.
				if (!empty($_POST['SendOTP'])) {
					// update user mobile, in case mobile number is changed
					$user->mobile = $_POST['User']['mobile'];
					$user->saveNode(false);

					$this->sendOTP($user);
				} else if (!empty($_POST['User'])) {
					$user->mobile_authtoken_verify = $_POST['User']['mobile_authtoken_verify'];

					$user->setScenario('verifyMobile');

					$isValid = $user->validate(array('mobile_authtoken_verify'));

					// Check verification code
					if ($isValid) {
						SystemEvent::add('Activation via Website - Success ', 'Username: ' . $user->username, 'Account');

						// user is activated
						$user->activate();

						// send activation success email
						$user->sendActivationSuccessEmail();

						// Send activation notification to Propsage administration
						$user->sendActivationNotificationToAdmin();

						$this->render('activationSuccess');
						Yii::app()->end();
					} else {
						// Do nothing.
					}
				}

//                unset($user->mobile_authtoken);
				// Display Mobile Verification Form
				$this->render('mobileVerification', array(
					'user' => $user,
				));
			} else {
				$this->render('activationError');
			}
		} else {
			$this->render('activationError');
		}
	}

	public function sendOTP($user) {
		$sentTimeLimit = strtotime($user->mobile_authtoken_sent_time) + (15 * 60); // 15 Minutes
		// OTP not generated or expired, generate new one.
		if (time() > $sentTimeLimit || empty($user->mobile_authtoken)) {
			// Generate random number
			$otp = rand(0, 99999999);
			$otp = str_pad($otp, 8, "0", STR_PAD_LEFT);

			$user->mobile_authtoken = $otp;
			$user->mobile_authtoken_sent_time = new CDbExpression('UTC_TIMESTAMP()');
			$user->saveNode(false, array('mobile_authtoken', 'mobile_authtoken_sent_time'));

			$message = "Your OTP is {$otp}.\n";
			$message .= "This password will expire in 15 minutes time.\n";

			$sms = new SMSOut($message, $user->mobile, "PROPSAGE");

			if ($sms->send()) {
				PsSystemMessage::add("One-Time Password sent to {$user->mobile}.", 'success');
			} else {
				PsSystemMessage::add("Error sending One-Time Password. Please try again.", "error");
			}
		}
		// OTP still active, tell user to wait until expired and try again
		else {
			$timeLeft = floor(($sentTimeLimit - time()) / 60);

			SystemMessage::add("One-time password already sent. If you did not receive it, please try again in " . $timeLeft . " minutes.", "error");
		}
	}

	/**
	 * Resends the activation email of the user.
	 */
	public function actionResendActivation($username) {
		$user = User::model()->findByAttributes(array('username' => $username));

		if ($user->status == User::STATUS_NOACTIVE) { // indicate the variable to define whether want this function or not
			if ($user->sendActivationEmail()) {
				PsSystemMessage::add("Activation Email sent to {$user->email}.", 'success');
			} else {
				PsSystemMessage::add("Error sending activation email.", "error");
			}
		} else if ($user->status == User::STATUS_DISABLED) {
			PsSystemMessage::add("Account cannot be activated.", "error");
		} else {
			PsSystemMessage::add("Account is already activated.", "info");
		}

		$this->redirect(array('/account/login'));
	}

	public function actionIdentify() {
		$this->layout = '//layouts/index2_nomenu';

		$referrer = $this->loadReferrer();

		if (isset($_POST['license_no'])) {
			$license_no = $_POST['license_no'];

			// Find User
			$user = User::model()->findByAttributes(array('license_no' => strtoupper($license_no)));

			// if agent is not found in local db, grab from cea database
			if ($user == null) {
				$user = PsCEADataGrabber::grabAgent($license_no);
			}

			// if agent cant be found on cea website, show error.
			if ($user == null) {
				// Log Event
				SystemEvent::add('Identify Failure', 'License No. Entered: ' . $license_no, 'Account');

				// Cannot find agent
				PsSystemMessage::add('License number not found in our database. Please contact customer support.', 'error');
			} else {
				// Log Event
				SystemEvent::add('Identify Success', 'License No. Entered: ' . $license_no, 'Account');

				if ($referrer != null) {
					$this->redirect(array('register', 'license_no' => $license_no, 'referrer' => $_GET["referrer"]));
				} else {
					$this->redirect(array('register', 'license_no' => $license_no));
				}
			}
		}

		$this->render('identify', array('referrer' => $referrer));
	}

	public function actionRegister($license_no) {
		$this->layout = '//layouts/index2_nomenu';

		$user = User::model()->findByAttributes(array('license_no' => strtoupper($license_no)));

		$referrer = $this->loadReferrer();

		// if user is inactive
		if ($user != null) {
			// User is activated
			if ($user->status == User::STATUS_ACTIVE) {
				$this->render('activationAlreadyCompleted');
			} else if ($user->status == User::STATUS_DISABLED) {
				$this->render('activationBanned');
			}
			// User is pending activation
			else if ($user->status == User::STATUS_NOACTIVE && is_string($user->password) && strlen($user->password) > 0) {
				$resendActivationEmailLink = CHtml::link('Resend Activation Email', array('/account/resendActivation', 'username' => $user->username), array('class' => 'resend-link'));

				$this->render('accountPendingActivation', array(
					'resendActivationEmailLink' => $resendActivationEmailLink,
				));
			}
			// User has not registered
			else {
				if (isset($_POST['User'])) {
					$user->setScenario('quickregister');
					$user->setScenario('quickregister');

					$user->attributes = $_POST['User'];
					$user->version = '3.0';

					if ($referrer != null) {
						$user->referrer_user_id = $referrer->id;
					} else {
						$user->referrer_user_id = null;
					}

					$valid = $user->validate(array('nric', 'agency_id', 'email', 'mobile', 'password'));

					if ($valid) {
						$transaction = Yii::app()->db->beginTransaction();

						try {
							if ($user->saveNode(false)) {
								$authAssignment = new UserAuthAssignment;
								$authAssignment->itemname = "DefaultAgent";
								$authAssignment->userid = $user->id;
								$authAssignment->save(false);

								if ($user->sendActivationEmail()) {

									$this->render('success', array(
										'email' => $user->email,
									));
								} else {
									$this->render('error', array(
										'email' => $user->email,
									));
								}

								$transaction->commit();

								Yii::app()->end();
							}
						} catch (Exception $e) {
							$transaction->rollback();
						}
					} else {
//                        dump($user->getErrors());
					}
				}

				$this->render('quickregister', array(
					'user' => $user,
					'referrer' => $referrer,
				));
			}
		} else {
			// User is not found in database, redirect back to identify page.
			if ($referrer != null) {
				$this->redirect(array('/account/identify', 'referrer' => $_GET["referrer"]));
			} else {
				$this->redirect(array('/account/identify'));
			}
		}
	}

	public function actionLogin($msg = '', $shortname = '') {
		if ($shortname != '') {
			$agency = Agency::model()->findByAttributes(array(
				'shortname' => $shortname
			));
		} else if ($this->_agency instanceof Agency) {
			$agency = $this->_agency;
		}

		if ($msg != '') {
			PsSystemMessage::add($msg, 'info', false);
			$this->redirect(array('/account/login'));
		}

		$model = new LoginForm;
		// collect user input data
		if (isset($_POST['LoginForm'])) {
			$model->attributes = $_POST['LoginForm'];

			$loginSuccess = $model->validate() && $model->login();

			// validate user input and redirect to the dashboard if valid
			$name = 'Login ' . ($loginSuccess ? 'Success' : 'Failure');
			$description = 'Username: ' . $model->username;
			if ($loginSuccess == false) {
				$reason = trim($model->getError('username') . "," . $model->getError('password'), ',');

				$description .= ', Reason: "' . $reason . '"';
			}

			SystemEvent::add($name, $description, 'Login');

			if ($loginSuccess) {
//				$this->redirectToReturnUrl('/' . Yii::app()->user->model->version . '/' . strtolower($model->app) . '/' . Yii::app()->user->model->agency->settings['UserProfile']['DefaultStartPage'] . '/');
				$this->redirectToReturnUrl('/' . Yii::app()->user->model->version . '/' . strtolower($model->app) . '/tickets/');
			}
		}

		if ($agency instanceof Agency) {
			$this->layout = '//layouts/plain';

			$this->render('/account/login_custom_combined', array('model' => $model, 'agency' => $agency, 'shortname' => $shortname));
		} else {
			$this->layout = '//layouts/main_no_logo';

			// display the login form
			$this->render('/account/login', array('model' => $model, 'agency' => $agency, 'shortname' => $shortname));
		}
	}

	/**
	 * Action to login a user with a valid, non-expired login_token
	 * @param type $login_token
	 */
	public function actionTokenLogin($app, $login_token) {
		$criteria = new CDbCriteria();
		$criteria->compare('token', UserSecurityHelper::hash($login_token));
		$criteria->addCondition('t.create_time + INTERVAL 5 MINUTE > UTC_TIMESTAMP()');

		$userLoginToken = UserLoginToken::model()->find($criteria);

		if ($userLoginToken !== null) {
			$user = $userLoginToken->user;
			$identity = PsUserIdentity::impersonate($user->id);
			if ($identity) {
				$psWebUser = new PsWebUser();
				$psWebUser->allowAutoLogin = true;
				$psWebUser->autoRenewCookie = true;
				$psWebUser->loginUrl = '/account/login';

				$psWebUser->init();

				if ($psWebUser->login($identity, 86400)) {
					$agency = $user->agency;
					
					SystemEvent::add('Login Success', 'Token: ' . $login_token, 'Login');
					$this->redirectToReturnUrl('/' . $user->version . '/' . $app . '/' . $agency->settings['UserProfile']['DefaultStartPage'] . '/');
				}
			}
		} else {
			SystemEvent::add('Login Failure', 'Invalid Token: ' . $login_token, 'Login');
			// token not found, redirect to login page
			$this->redirect(array('/account/login'));
		}
	}

	/**
	 * Action to login a user with a valid, non-expired login_token
	 * @param type $access_token
	 */
	public function actionOauthLogin($access_token) {
		$response = array();

		$oauthSessionAccessToken = OauthSessionAccessTokens::model()->findByAttributes(array(
			'access_token' => $access_token
		));

		if ($oauthSessionAccessToken !== null) {
			$oauthSession = $oauthSessionAccessToken->session;
			$userId = $oauthSession->owner_id;

			$user = User::model()->findByAttributes(array(
				'status' => User::STATUS_ACTIVE,
				'id' => $userId
			));

			if ($user != null) {
				$agency = $user->agency;
				$identity = PsUserIdentity::impersonate($user->id);
				if ($identity) {
					$psWebUser = new PsWebUser();
					$psWebUser->allowAutoLogin = true;
					$psWebUser->autoRenewCookie = true;
					$psWebUser->loginUrl = '/account/login';

					$psWebUser->init();

					if ($psWebUser->login($identity, 86400)) {
						SystemEvent::add('Login Success', 'Token: ' . $access_token, 'Login');
						$this->redirectToReturnUrl('/' . $user->version . '/topachiever/' . $agency->settings['UserProfile']['DefaultStartPage'] . '/');
					}
				}
			} else {
				$response['error'] = 'Unknown user';
			}
		} else {
			SystemEvent::add('Login Failure', 'Invalid Token: ' . $access_token, 'Login');
			$response['error'] = 'Invalid token.';
		}

		print json_encode($response);
	}
	
	public function actionSecureLogin($data, $timestamp, $app_id, $hash) {
		try {
			// check timestamp
			if (time() - $timestamp > self::SECURE_LOGIN_TIMEOUT) {
				throw new CHttpException(401, 'Request Expired');
			}

			// check api key
			$criteria = new CDbCriteria();
			$criteria->compare('t.deleted', 0);
			$criteria->compare('t.application_id', $app_id);

			// TODO: CACHE THE api query in memcache
			$apiKey = ApiKey::model()->find($criteria);

			if ($apiKey == null) {
				throw new CHttpException(401, 'Invalid Authentication');
			} else {
				// Validate hash
				$hash2 = UserSecurityHelper::hash_hmac($data . '|' . $app_id . '|' . $timestamp, $apiKey->secret_key);

				if ($hash === $hash2) { // message is validated
					// decrypt the data using
					$username = UserSecurityHelper::decrypt($data, $apiKey->secret_key);

					$user = User::model()->findByAttributes(array(
						'status' => User::STATUS_ACTIVE,
						'agency_id' => $apiKey->agency_id,
						'username' => $username
					));

					if ($user === null) {
						throw new CHttpException(401, 'Invalid or Inactive user');
					} else { // valid active user found from the same agency as the api key
						$agency = $user->agency;
						
						$app = 'topachiever';
						$identity = PsUserIdentity::impersonate($user->id);
						if ($identity) {
							$psWebUser = new PsWebUser();
							$psWebUser->allowAutoLogin = true;
							$psWebUser->autoRenewCookie = true;
							$psWebUser->loginUrl = '/account/login';

							$psWebUser->init();

							if ($psWebUser->login($identity, 86400)) {
								SystemEvent::add('Login Success', 'Username: ' . $username . '|data: ' . $data, 'Login');
								$this->redirectToReturnUrl('/' . $user->version . '/' . $app . '/' . $agency->settings['UserProfile']['DefaultStartPage'] . '/');
							}
						}
					}
				} else {
					throw new CHttpException(401, 'Invalid Authentication');
				}
			}
		} catch (CHttpException $e) {
			header("HTTP/1.0 " . $e->statusCode . " " . $e->getMessage());			
			SystemEvent::add('Login Failure', $e->getMessage() . '. Code:' . $e->statusCode, 'Login');
		}
	}

	public function actionAgencyLogin($shortname = '') {
		$agency = Agency::model()->findByAttributes(array(
			'shortname' => $shortname
		));

		$model = new LoginForm;

		// collect user input data
		if (isset($_POST['LoginForm'])) {
			$model->attributes = $_POST['LoginForm'];

			$loginSuccess = $model->validate() && $model->login();

			// validate user input and redirect to the dashboard if valid
			$name = 'Login ' . ($loginSuccess ? 'Success' : 'Failure');
			$description = 'Username: ' . $model->username;
			if ($loginSuccess == false) {
				$reason = trim($model->getError('username') . "," . $model->getError('password'), ',');

				$description .= ', Reason: "' . $reason . '"';
			}

			SystemEvent::add($name, $description, 'Login');

			if ($loginSuccess) {
				$agency = Yii::app()->user->model->agency;
				
				$this->redirectToReturnUrl('/' . Yii::app()->user->model->version . '/prestige/') . $agency->settings['UserProfile']['DefaultStartPage'] . '/';
			}
		}

		$this->layout = '//layouts/plain';

		$this->render('/account/login_custom', array('model' => $model, 'agency' => $agency, 'mode' => 'Agency'));
	}

	public function actionAgentLogin($shortname = '') {
		$agency = Agency::model()->findByAttributes(array(
			'shortname' => $shortname
		));

		$model = new LoginForm;

		// collect user input data
		if (isset($_POST['LoginForm'])) {
			$model->attributes = $_POST['LoginForm'];

			$loginSuccess = $model->validate() && $model->login();

			// validate user input and redirect to the dashboard if valid
			$name = 'Login ' . ($loginSuccess ? 'Success' : 'Failure');
			$description = 'Username: ' . $model->username;
			if ($loginSuccess == false) {
				$reason = trim($model->getError('username') . "," . $model->getError('password'), ',');

				$description .= ', Reason: "' . $reason . '"';
			}

			SystemEvent::add($name, $description, 'Login');

			if ($loginSuccess) {
				$this->redirectToReturnUrl('/' . Yii::app()->user->model->version . '/topachiever/' . $agency->settings['UserProfile']['DefaultStartPage'] . '/');
			}
		}

		$this->layout = '//layouts/plain';

		$this->render('/account/login_custom', array('model' => $model, 'agency' => $agency, 'mode' => 'Salesperson'));
	}

	public function actionForgetPassword($username = '', $shortname = '') {
		$agency = Agency::model()->findByAttributes(array(
			'shortname' => $shortname
		));

		$this->layout = '//layouts/index2';

		$model = new ForgetPasswordForm;
		$session = Yii::app()->session;

		if (isset($_POST['ForgetPasswordForm'])) {
			$username = $_POST['ForgetPasswordForm']['username'];
		}

		if (!empty($username)) {
			$session->add('ForgetPasswordForm', $model);
			$model->username = $username;

			if ($model->validate()) {
				$user = User::model()->findByAttributes(array('username' => $username));

				if (isset($user)) {
					if ($user->status == User::STATUS_ACTIVE) {
						if (!empty($user->email)) {
							$activation_url = $this->createAbsoluteUrl('account/resetNewPassword', array("activkey" => $user->activkey, "username" => $user->username));

							$tokenList = array();
							$tokenList["activationURL"] = $activation_url;
							$tokenList["username"] = $user->getDisplayName();

							$subject = Yii::t('', "Change / Reset of Password from PropSage {site_name}", array('{site_name}' => Yii::app()->name));

							$mailer = new Mailer();
							$mailer->layout = Yii::getPathOfAlias('common') . "/templates/emails/layouts/default.tpl";
							$mailer->addSender(Yii::app()->params["noreplyEmail"], Yii::app()->params["noreplyName"]);
							$mailer->addRecipient($user->email, $user->getDisplayName());
							$mailer->addSubject($subject);

							$mailer->createHTMLMail(Yii::getPathOfAlias('common') . "/templates/emails/account/acctForgetPasswordHTML.tpl", $tokenList);
							$mailer->sendMail();

							$session->remove('ForgetPasswordForm');

							$maskedEmail = TextFormatter::maskEmail($user->email, '.', 50);
							$view = '/account/forgetPasswordSuccess';
							$data = array('maskedEmail' => $maskedEmail);
						} else {
							$model->addError('username', "Account does not have an email. Please kindly contact your administrator or email <a href=\"mailto:support@propsage.com\">support@propsage.com</a> to reset your password.");
						}
					} else {
						$resendActivationEmailLink = CHtml::link('Resend Activation Email', array('/account/resendActivation', 'username' => $user->username), array('class' => 'resend-link'));
						$model->addError('username', 'Account is not activated, please check your email. <br/>' . $resendActivationEmailLink);
					}
				} else {
					$model->addError('username', "Account does not exist.");
				}
			}
		} else {
			//echo "valication fail";
		}

		if (!isset($view)) {
			$view = '/account/forgetPassword';
			$data = array('model' => $model);
		}

		if (!empty($shortname) && $agency !== null) {
			$view .= '_custom';
			$data['agency'] = $agency;
			$this->layout = '//layouts/plain';
		}

		if (isset($_GET['datatype']) && $_GET['datatype'] == 'jsonp') {
			$response = array();
			if ($model->hasErrors()) {
				$errors = $model->getErrors();
				$response['result'] = 'failure';
				$response['errorMsg'] = current($errors);
			} else {
				$response['result'] = 'success';
				$response['successMsg'] = 'Recovery Email sent to ' . $maskedEmail;
			}

			$output = json_encode($response);
			if (isset($_GET['callback'])) { // jsonp request
				$output = $_GET["callback"] . "(" . $output . ");";
			}

			print $output;
		} else {
			$this->render($view, $data);
		}
	}

	public function actionResetNewPassword() {
		$this->layout = '//layouts/index2';

		$username = $_GET['username'];
		$activkey = $_GET['activkey'];

		if ($username && $activkey) {
			$model = User::model()->findByAttributes(array('username' => $username, 'activkey' => $activkey));

			if ($model == null) {
				PsSystemMessage::add('Invalid Action. Please try again.', 'error');
				$this->redirect(array('/account/forgetpassword'));
			} else {
				$model->setScenario('resetPassword');

				if (isset($_POST['User'])) {
					$model->attributes = $_POST['User'];

					if ($model->validate(array('new_password', 'password_repeat'))) {

						$model->password = $model->new_password;
						$model->activkey = UserSecurityHelper::hash(microtime() . $model->password);

						if ($model->saveNode()) {
							PsSystemMessage::add('Password Changed.', 'success');
							$this->redirect(array('/account/login'));
						} else {
							throw new CHttpException(500, "An unexpected error has occured. Please try again.");
						}
					} else {
//                        dump($model->getErrors());
					}
				}

				$this->render('/account/resetNewPassword', array('model' => $model));
			}
		}
	}

	public function actionLogout($redirectTo = '/index.html', $msg = '') {
		if (Yii::app()->user->hasState('loginToken')) {
			Yii::app()->user->model->removeLoginToken(Yii::app()->user->getState('loginToken'));
		}

		$agencyLogoutUrl = Yii::app()->user->model->agency->logout_url;

		Yii::app()->user->logout();
		unset(Yii::app()->request->cookies['hideWelcome']);

		if (!empty($agencyLogoutUrl)) {
			$redirectTo = $agencyLogoutUrl;
		}

		if (is_array($redirectTo)) {
			$redirectTo['msg'] = $msg;
		} else {
			$redirectTo .= '?msg=' . $msg;
		}

		$this->redirect($redirectTo);
	}

	public function loadReferrer() {
		// referrer id must be set and user cannot refer him/herself
		if (!empty($_GET["referrer"]) && ($_GET["license_no"] != $_GET["referrer"])) {
			$referrer_id = $_GET["referrer"];

			$referrer = User::model()->findByAttributes(array('username' => $referrer_id));

			if ($referrer->status == User::STATUS_NOACTIVE) {
				$referrer = null;
			}
		} else {
			$referrer = null;
		}

		return $referrer;
	}

	/**
	 * Performs the AJAX validation.
	 * @param CModel the model to be validated
	 */
	protected function performAjaxValidation($model, $form = null) {
		if (Yii::app()->request->isAjaxRequest && isset($_POST['ajax'])) {
			$class = get_class($model);
			if (isset($_POST['attributes']) && is_array($_POST['attributes'][$class]))
				$attributes = $_POST['attributes'][$class];
			else
				$attributes = null;
			echo CActiveForm::validate($model, $attributes);
			Yii::app()->end();
		}
	}

	public function redirectToReturnUrl($defaultRedirect) {
		$redirectUrl = Yii::app()->user->getReturnUrl($defaultRedirect);

		if ($redirectUrl == Yii::app()->user->loginUrl) {
			$redirectUrl = $defaultRedirect;
		}

		if (strstr($redirectUrl, $defaultRedirect) == false) {
			$redirectUrl = $defaultRedirect;
		}

		$this->redirect($redirectUrl);
	}

}
